<template>
  <div class="earth-container">
    <div ref="earthRef" class="earth-canvas"></div>
    <!-- HTML Sprite组件容器 -->
    <div class="html-sprites-container">
      <HTMLSprite
        v-for="(sprite, index) in htmlSprites"
        :key="sprite.countryName"
        :country-name="sprite.countryName"
        :position="sprite.position"
        :texture="sprite.texture"
        :screen-x="sprite.screenX"
        :screen-y="sprite.screenY"
        :visible="sprite.visible"
        @click="handleSpriteClick"
        @hover="handleSpriteHover"
      />
    </div>
  </div>
</template>

<script setup lang="ts">
// @note 此案例绘制的边界线最精准
import { ref, onMounted, onBeforeUnmount, reactive, nextTick } from 'vue'
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
// @ts-ignore
import worldGeoData from '@/assets/json/worldGeoData.json'
// @ts-ignore
import countryData from '@/assets/json/countryData.json'
// 引入HTML Sprite组件
import HTMLSprite from '@/components/HTMLSprite.vue'

// 类型定义
interface CountryInfo {
  name: string
  capital?: string
  population?: number
  area?: number
  languages?: string[]
  currencies?: { name: string }[]
}

// HTML Sprite类型定义
interface HTMLSpriteData {
  countryName: string
  position: THREE.Vector3
  texture: string
  screenX: number
  screenY: number
  visible: boolean
}

// 引用
const earthRef = ref<HTMLDivElement | null>(null)

// 响应式数据
const selectedCountryInfo = ref<CountryInfo | null>(null)
const infoPanelPosition = reactive({ x: 0, y: 0 })
const htmlSprites = ref<HTMLSpriteData[]>([])



// Three.js 对象
let scene: THREE.Scene
let camera: THREE.PerspectiveCamera
let renderer: THREE.WebGLRenderer
let controls: OrbitControls
let earthGroup: THREE.Group
let countryMeshes: Map<string, THREE.Mesh> = new Map()

// 添加旋转控制变量
let isRotating = true
let isMouseOver = false

// 鼠标事件处理函数引用
let mouseEnterHandler: (() => void) | null = null
let mouseLeaveHandler: (() => void) | null = null

// 初始化场景
const initScene = () => {
  if (!earthRef.value) return

  // 创建场景
  scene = new THREE.Scene()
  scene.background = new THREE.Color(0x000b1a)

  // 创建相机
  camera = new THREE.PerspectiveCamera(
    45,
    window.innerWidth / window.innerHeight,
    0.1,
    1000
  )
  camera.position.set(0, 0, 3)

  // 创建渲染器
  renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true })
  renderer.setSize(window.innerWidth, window.innerHeight)
  renderer.setPixelRatio(window.devicePixelRatio)
  earthRef.value.appendChild(renderer.domElement)
  
  // 调试日志
  console.log('Camera and renderer initialized:', { camera, renderer })

  // 添加光源
  const ambientLight = new THREE.AmbientLight(0xffffff, 0.6)
  scene.add(ambientLight)

  const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8)
  directionalLight.position.set(5, 3, 5)
  scene.add(directionalLight)

  // 创建控制器
  controls = new OrbitControls(camera, renderer.domElement)
  controls.enableDamping = true
  controls.dampingFactor = 0.05
  controls.enableRotate = true  // 确保启用旋转

  // 创建地球组
  earthGroup = new THREE.Group()
  scene.add(earthGroup)

  // 创建地球
  createEarth()

  // 添加事件监听器
  window.addEventListener('resize', onWindowResize)
  
  // 添加鼠标事件监听器
  if (renderer.domElement) {
    mouseEnterHandler = () => {
      isMouseOver = true
      isRotating = false // 鼠标移入时停止旋转
    }
    
    mouseLeaveHandler = () => {
      isMouseOver = false
      isRotating = true // 鼠标移出时开始旋转
    }
    
    renderer.domElement.addEventListener('mouseenter', mouseEnterHandler)
    renderer.domElement.addEventListener('mouseleave', mouseLeaveHandler)
  }
  
  // 在下一帧创建国家边界，确保相机已正确初始化
  requestAnimationFrame(() => {
    // 使用默认贴图创建国家
    createCountries()
    
    // 如果要使用自定义贴图，有几种方式：
    // 方式1: 使用预定义的自定义贴图函数
    // createCountriesWithCustomSprites([
    //   '/src/assets/img/your-custom-image1.png',
    //   '/src/assets/img/your-custom-image2.png',
    //   '/src/assets/img/your-custom-image3.png'
    // ])
    
    // 方式2: 在创建国家后动态更新贴图
    // updateRegionSprites([
    //   '/src/assets/img/your-custom-image1.png',
    //   '/src/assets/img/your-custom-image2.png'
    // ])
  })
}

// 创建地球球体
const createEarth = () => {
  // 地球基础球体
  const earthGeometry = new THREE.SphereGeometry(1, 64, 64)
  
  // 创建纹理加载器
  const textureLoader = new THREE.TextureLoader()
  
  // 加载地球纹理
  const earthTexture = textureLoader.load('/earth.jpg')
  
  // 地球材质
  const earthMaterial = new THREE.MeshPhongMaterial({
    map: earthTexture,
    specular: new THREE.Color(0x333333),
    shininess: 5
  })
  
  // 创建地球网格
  const earthMesh = new THREE.Mesh(earthGeometry, earthMaterial)
  earthGroup.add(earthMesh)
}

// 为各个区域添加HTML Sprite贴图纹理
const addRegionSprites = () => {
  console.log('Adding region sprites, countryMeshes count:', countryMeshes.size)
  
  // 定义不同类型的贴图资源 - 可以根据需要自定义这些图片
  const spriteTextures = [
    './img/virus1.png',
    './img/virus2.png',
    './img/virus3.png'
  ]
  
  // 清空现有的HTML Sprites
  htmlSprites.value = []
  
  // 遍历所有国家网格添加HTML Sprite
  countryMeshes.forEach((mesh, countryName) => {
    // 提取国家名称（去除索引后缀）
    const cleanCountryName = countryName.split('_')[0]
    
    // 为每个国家随机选择一个贴图
    const randomTexture = spriteTextures[Math.floor(Math.random() * spriteTextures.length)]
    
    // 计算国家区域的质心位置
    let centroid = new THREE.Vector3()
    
    // 获取国家网格中的区域网格（第二个子对象）
    if (mesh.children && mesh.children.length > 1) {
      const areaMesh = mesh.children[1] // 区域网格是第二个子对象
      const geometry = areaMesh.geometry
      
      // 获取几何体的顶点
      const positionAttribute = geometry.getAttribute('position')
      if (positionAttribute) {
        // 计算所有顶点的平均位置作为质心
        let sumX = 0, sumY = 0, sumZ = 0
        const count = positionAttribute.count
        
        for (let i = 0; i < count; i++) {
          sumX += positionAttribute.getX(i)
          sumY += positionAttribute.getY(i)
          sumZ += positionAttribute.getZ(i)
        }
        
        // 计算平均值
        centroid.set(sumX / count, sumY / count, sumZ / count)
        
        // 将质心位置应用网格的世界变换
        centroid.applyMatrix4(mesh.matrixWorld)
      } else {
        // 如果无法获取顶点，则回退到包围盒中心
        const boundingBox = new THREE.Box3().setFromObject(mesh)
        boundingBox.getCenter(centroid)
      }
    } else {
      // 如果无法获取区域网格，则回退到包围盒中心
      const boundingBox = new THREE.Box3().setFromObject(mesh)
      boundingBox.getCenter(centroid)
    }
    
    // 将HTML Sprite数据添加到响应式数组中
    htmlSprites.value.push({
      countryName: cleanCountryName, // 使用清理后的国家名称
      position: centroid.clone(),
      texture: randomTexture,
      screenX: 0, // 初始值将在updateHTMLSpritePositions中更新
      screenY: 0  // 初始值将在updateHTMLSpritePositions中更新
    })
  })
  
  console.log('HTML Sprites added, count:', htmlSprites.value.length)
  console.log('HTML Sprites data:', htmlSprites.value)
  
  // 在下一帧更新所有HTML Sprites的位置
  nextTick(() => {
    updateHTMLSpritePositions()
  })
}

// 自定义贴图函数 - 您可以使用这个函数来设置自己的贴图
const setCustomRegionSprites = (customTextures: string[]) => {
  // 清空现有的HTML Sprites
  htmlSprites.value = []
  
  // 遍历所有国家网格添加自定义HTML Sprite
  countryMeshes.forEach((mesh, countryName) => {
    // 为每个国家选择一个贴图（可以按顺序或随机）
    const textureIndex = Array.from(countryMeshes.keys()).indexOf(countryName) % customTextures.length
    const texturePath = customTextures[textureIndex]
    
    // 计算国家区域的质心位置
    let centroid = new THREE.Vector3()
    
    // 获取国家网格中的区域网格（第二个子对象）
    if (mesh.children && mesh.children.length > 1) {
      const areaMesh = mesh.children[1] // 区域网格是第二个子对象
      const geometry = areaMesh.geometry
      
      // 获取几何体的顶点
      const positionAttribute = geometry.getAttribute('position')
      if (positionAttribute) {
        // 计算所有顶点的平均位置作为质心
        let sumX = 0, sumY = 0, sumZ = 0
        const count = positionAttribute.count
        
        for (let i = 0; i < count; i++) {
          sumX += positionAttribute.getX(i)
          sumY += positionAttribute.getY(i)
          sumZ += positionAttribute.getZ(i)
        }
        
        // 计算平均值
        centroid.set(sumX / count, sumY / count, sumZ / count)
        
        // 将质心位置应用网格的世界变换
        centroid.applyMatrix4(mesh.matrixWorld)
      } else {
        // 如果无法获取顶点，则回退到包围盒中心
        const boundingBox = new THREE.Box3().setFromObject(mesh)
        boundingBox.getCenter(centroid)
      }
    } else {
      // 如果无法获取区域网格，则回退到包围盒中心
      const boundingBox = new THREE.Box3().setFromObject(mesh)
      boundingBox.getCenter(centroid)
    }
    
    // 将HTML Sprite数据添加到响应式数组中
    htmlSprites.value.push({
      countryName: countryName,
      position: centroid.clone(),
      texture: texturePath,
      screenX: 0, // 初始值将在updateHTMLSpritePositions中更新
      screenY: 0  // 初始值将在updateHTMLSpritePositions中更新
    })
  })
  
  // 在下一帧更新所有HTML Sprites的位置
  nextTick(() => {
    updateHTMLSpritePositions()
  })
}

// 动态更新贴图的函数 - 可以在运行时调用此函数来更改贴图
const updateRegionSprites = (newTextures?: string[]) => {
  // 如果提供了新的贴图路径，则使用新的贴图
  if (newTextures && newTextures.length > 0) {
    setCustomRegionSprites(newTextures)
  } else {
    // 否则重新应用默认贴图
    addRegionSprites()
  }
}

// 更新所有HTML Sprites的位置
const updateHTMLSpritePositions = () => {
  if (!camera || !renderer) return
  
  // 定义需要保留的国家列表
  const countriesToKeep = ['China', 'United States', 'United Kingdom', 'France']
  
  // 过滤出需要保留的国家
  const filteredSprites = htmlSprites.value.filter(sprite => 
    countriesToKeep.includes(sprite.countryName)
  )
  
  const canvas = renderer.domElement
  
  // 确保获取正确的canvas尺寸
  const canvasWidth = canvas.clientWidth || canvas.width
  const canvasHeight = canvas.clientHeight || canvas.height
  
  // 创建相机方向向量用于背面剔除
  const cameraDirection = new THREE.Vector3()
  camera.getWorldDirection(cameraDirection)
  
  // 创建一个新的数组来存储更新后的sprite数据
  const updatedSprites = filteredSprites.map((sprite) => {
    // 创建一个世界坐标位置向量
    let worldPosition = sprite.position.clone()
    
    // 应用缩放以稍微抬高sprite使其在地球表面上方显示
    worldPosition.multiplyScalar(1.01) // 减小抬高量以提高准确性
    
    // 如果提供了地球组，需要将本地坐标转换为世界坐标
    if (earthGroup) {
      // 将本地坐标应用地球组的变换矩阵转换为世界坐标
      worldPosition.applyMatrix4(earthGroup.matrixWorld)
    }
    
    // 计算从地球中心到sprite位置的向量
    const earthCenter = new THREE.Vector3(0, 0, 0)
    if (earthGroup) {
      earthCenter.applyMatrix4(earthGroup.matrixWorld)
    }
    
    const spriteDirection = new THREE.Vector3().subVectors(worldPosition, earthCenter).normalize()
    
    // 计算sprite方向与相机方向的点积，用于判断是否在正面
    const dot = spriteDirection.dot(cameraDirection)
    
    // 如果点积小于等于0.1（略微放宽条件），说明sprite在地球背面或接近背面，应该隐藏
    if (dot <= 0.1) {
      return {
        ...sprite,
        screenX: 0,
        screenY: 0,
        visible: false
      }
    }
    
    // 将3D世界坐标转换为标准化设备坐标(NDC)
    const ndcPosition = worldPosition.clone().project(camera)
    
    const widthHalf = canvasWidth / 2
    const heightHalf = canvasHeight / 2
    
    // 将NDC坐标转换为屏幕坐标
    // 注意：NDC坐标范围是[-1, 1]，需要转换为[0, width]和[0, height]的屏幕坐标
    const screenX = (ndcPosition.x * widthHalf) + widthHalf
    const screenY = -(ndcPosition.y * heightHalf) + heightHalf
    
    // 检查坐标是否有效
    if (isNaN(screenX) || isNaN(screenY)) {
      console.warn('Invalid screen coordinates calculated for sprite:', sprite.countryName)
      return {
        ...sprite,
        screenX: 0,
        screenY: 0,
        visible: false
      }
    }
    
    // 返回更新后的sprite数据
    return {
      ...sprite,
      screenX,
      screenY,
      visible: true
    }
  })
  
  // 更新htmlSprites数组以触发重新渲染
  htmlSprites.value = updatedSprites
}

// HTML Sprite事件处理函数
const handleSpriteClick = (countryName: string) => {
  console.log('Sprite clicked for country:', countryName)
  // 这里可以添加点击事件处理逻辑
}

const handleSpriteHover = (countryName: string, isHover: boolean) => {
  console.log(`Sprite hover ${isHover ? 'enter' : 'leave'} for country:`, countryName)
  // 这里可以添加悬停事件处理逻辑
}

// 创建国家边界和区域
const createCountries = () => {
  // 清空之前的国家网格
  countryMeshes.clear()
  
  // 遍历GeoJSON数据创建每个国家
  worldGeoData.features.forEach((feature: any) => {
    const countryName = feature.properties.name
    const coordinates = feature.geometry.coordinates
    const type = feature.geometry.type
    
    // 为每个国家生成随机颜色
    const colorHex = '#' + Math.floor(Math.random() * 16777215).toString(16).padStart(6, '0')
    const color = new THREE.Color(colorHex)
    
    // 根据几何类型处理坐标
    if (type === 'MultiPolygon') {
      coordinates.forEach((polygon: any, index: number) => {
        // 为每个子多边形创建网格
        const mesh = createCountryMesh(polygon, color, `${countryName}_${index}`)
        if (mesh) {
          earthGroup.add(mesh)
          countryMeshes.set(`${countryName}_${index}`, mesh)
        }
      })
    } else if (type === 'Polygon') {
      const mesh = createCountryMesh(coordinates, color, countryName)
      if (mesh) {
        earthGroup.add(mesh)
        countryMeshes.set(countryName, mesh)
      }
    }
  })
  
  // 为各个区域添加Sprite贴图纹理
  addRegionSprites()
}

// 使用自定义贴图创建国家边界和区域
const createCountriesWithCustomSprites = (customTextures: string[]) => {
  // 清空之前的国家网格
  countryMeshes.clear()
  
  // 遍历GeoJSON数据创建每个国家
  worldGeoData.features.forEach((feature: any) => {
    const countryName = feature.properties.name
    const coordinates = feature.geometry.coordinates
    const type = feature.geometry.type
    
    // 为每个国家生成随机颜色
    const colorHex = '#' + Math.floor(Math.random() * 16777215).toString(16).padStart(6, '0')
    const color = new THREE.Color(colorHex)
    
    // 根据几何类型处理坐标
    if (type === 'MultiPolygon') {
      coordinates.forEach((polygon: any, index: number) => {
        // 为每个子多边形创建网格
        const mesh = createCountryMesh(polygon, color, `${countryName}_${index}`)
        if (mesh) {
          earthGroup.add(mesh)
          countryMeshes.set(`${countryName}_${index}`, mesh)
        }
      })
    } else if (type === 'Polygon') {
      const mesh = createCountryMesh(coordinates, color, countryName)
      if (mesh) {
        earthGroup.add(mesh)
        countryMeshes.set(countryName, mesh)
      }
    }
  })
  
  // 为各个区域添加自定义Sprite贴图纹理
  setCustomRegionSprites(customTextures)
}



// 创建单个国家的网格
const createCountryMesh = (coordinates: any, color: THREE.Color, name: string): THREE.Mesh | null => {
  try {
    // 检查坐标是否存在
    if (!coordinates || coordinates.length === 0) {
      console.warn(`国家 ${name} 的坐标数据为空`)
      return null
    }
    
    // 处理第一个环（外环）
    const ring = coordinates[0]
    if (!ring || ring.length === 0) {
      console.warn(`国家 ${name} 的环坐标数据为空`)
      return null
    }
    
    // 创建国家边界线
    const linePoints: THREE.Vector3[] = []
    ring.forEach((coord: number[]) => {
      // 检查坐标点是否有效
      if (!coord || coord.length < 2) return
      
      const [longitude, latitude] = coord
      // 转换为3D坐标（略微抬高以避免z-fighting并改善填充效果）
      const phi = (90 - latitude) * Math.PI / 180
      const theta = (longitude + 180) * Math.PI / 180
      const radius = 1.03 // 进一步增加距离以改善填充效果
      
      const x = -Math.sin(phi) * Math.cos(theta) * radius
      const y = Math.cos(phi) * radius
      const z = Math.sin(phi) * Math.sin(theta) * radius
      
      linePoints.push(new THREE.Vector3(x, y, z))
    })
    
    // 如果点数不足，跳过这个网格
    if (linePoints.length < 3) {
      console.warn(`国家 ${name} 的点数不足 (${linePoints.length})`)
      return null
    }
    
    // 创建线条几何体
    const lineGeometry = new THREE.BufferGeometry().setFromPoints(linePoints)
    
    // 创建线条材质
    const lineMaterial = new THREE.LineBasicMaterial({
      color: color,
      transparent: true,
      opacity: 0.8
    })
    
    // 创建线条对象
    const line = new THREE.Line(lineGeometry, lineMaterial)
    line.userData = { countryName: name ? name.split('_')[0] : 'Unknown' }
    
    // 创建国家区域填充（使用优化的球面三角剖分）
    // 为了同时实现紧贴球面和正确填充，我们需要一种混合方法
    
    // 首先，创建一个略微抬高的区域网格以避免z-fighting
     const radius = 1.03 // 与边界线保持一致的高度
    
    // 收集所有点的球面坐标
    const sphericalPoints = []
    linePoints.forEach(point => {
      // 将点重新投影到略微抬高的球面上
      const length = Math.sqrt(point.x*point.x + point.y*point.y + point.z*point.z)
      if (length > 0) {
        const scaledX = point.x / length * radius
        const scaledY = point.y / length * radius
        const scaledZ = point.z / length * radius
        sphericalPoints.push(new THREE.Vector3(scaledX, scaledY, scaledZ))
      } else {
        sphericalPoints.push(new THREE.Vector3(point.x, point.y, point.z))
      }
    })
    
    // 使用更精细的三角剖分方法
    const vertices = []
    const indices = []
    
    // 添加所有边界点
    sphericalPoints.forEach(point => {
      vertices.push(point.x, point.y, point.z)
    })
    
    // 对于较小的区域，使用扇形三角剖分
    // 对于较大的区域，使用改进的算法
    if (sphericalPoints.length >= 3) {
      if (sphericalPoints.length <= 10) {
        // 小区域使用扇形三角剖分
        for (let i = 1; i < sphericalPoints.length - 1; i++) {
          indices.push(0, i, i + 1)
        }
      } else {
        // 大区域使用改进的重心三角剖分
        // 计算近似重心点
        let sumX = 0, sumY = 0, sumZ = 0
        sphericalPoints.forEach(point => {
          sumX += point.x
          sumY += point.y
          sumZ += point.z
        })
        
        const avgX = sumX / sphericalPoints.length
        const avgY = sumY / sphericalPoints.length
        const avgZ = sumZ / sphericalPoints.length
        
        // 将重心点投影到正确的球面半径上
        const centerLength = Math.sqrt(avgX*avgX + avgY*avgY + avgZ*avgZ)
        if (centerLength > 0) {
          const centerX = avgX / centerLength * radius
          const centerY = avgY / centerLength * radius
          const centerZ = avgZ / centerLength * radius
          
          // 添加重心点到顶点数组
          vertices.push(centerX, centerY, centerZ)
          const centerIndex = sphericalPoints.length
          
          // 创建三角形索引
          for (let i = 0; i < sphericalPoints.length; i++) {
            const nextIndex = (i + 1) % sphericalPoints.length
            indices.push(i, nextIndex, centerIndex)
          }
        } else {
          // 退回到简单的扇形三角剖分
          for (let i = 1; i < sphericalPoints.length - 1; i++) {
            indices.push(0, i, i + 1)
          }
        }
      }
    }
    
    // 创建缓冲几何体
    const areaGeometry = new THREE.BufferGeometry()
    const positions = new Float32Array(vertices)
    areaGeometry.setAttribute('position', new THREE.BufferAttribute(positions, 3))
    areaGeometry.setIndex(indices)
    areaGeometry.computeVertexNormals()
    
    // 创建区域材质（使用较深的颜色并设置透明度）
    const areaColor = color.clone()
    areaColor.offsetHSL(0, 0, -0.2) // 使填充颜色比边框颜色更深一些
    
    const areaMaterial = new THREE.MeshBasicMaterial({
      color: areaColor,
      transparent: true,
      opacity: 0.6,
      side: THREE.DoubleSide
    })
    
    // 创建区域网格
    const areaMesh = new THREE.Mesh(areaGeometry, areaMaterial)
    areaMesh.userData = { countryName: name ? name.split('_')[0] : 'Unknown' }
    
    // 创建一个组来包含线条和区域
    const countryGroup = new THREE.Group()
    countryGroup.add(line)
    countryGroup.add(areaMesh)
    countryGroup.userData = { countryName: name ? name.split('_')[0] : 'Unknown' }
    
    return countryGroup
  } catch (error) {
    console.warn(`创建国家 ${name} 网格时出错:`, error)
    return null
  }
}

// 鼠标点击事件处理
// 窗口大小调整处理
const onWindowResize = () => {
  if (!camera || !renderer) return
  
  camera.aspect = window.innerWidth / window.innerHeight
  camera.updateProjectionMatrix()
  renderer.setSize(window.innerWidth, window.innerHeight)
  
  // 更新HTML Sprites的位置
  updateHTMLSpritePositions()
}

// 动画循环
const animate = () => {
  requestAnimationFrame(animate)
  
  // 更新控制器
  if (controls) {
    controls.update()
  }
  
  // 地球自转动画
  if (earthGroup && isRotating) {
    earthGroup.rotation.y += 0.002 // 调整旋转速度
  }
  
  // 更新HTML Sprites的位置
  updateHTMLSpritePositions()
  
  // 渲染场景
  if (renderer && scene && camera) {
    renderer.render(scene, camera)
  }
}

// 组件挂载时初始化
onMounted(() => {
  initScene()
  animate()
})

// 组件卸载前清理
onBeforeUnmount(() => {
  window.removeEventListener('resize', onWindowResize)
  
  // 移除鼠标事件监听器
  if (renderer && renderer.domElement && mouseEnterHandler && mouseLeaveHandler) {
    renderer.domElement.removeEventListener('mouseenter', mouseEnterHandler)
    renderer.domElement.removeEventListener('mouseleave', mouseLeaveHandler)
  }
})


</script>

<style scoped>
.earth-container {
  width: 100%;
  height: 100%;
  position: relative;
  overflow: hidden;
}

.earth-canvas {
  width: 100%;
  height: 100%;
}

/* HTML Sprites样式 */
.html-sprites-container {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 10;
}

.html-sprites-container > div {
  pointer-events: auto;
}
</style>